#include "CTriangle2d.h"

CTriangle2d::CTriangle2d()
{

}


CTriangle2d::CTriangle2d( const CVector2d& v0, const CVector2d& v1, const CVector2d& v2 )
{
	m_v0 = v0;
	m_v1 = v1;
	m_v2 = v2;
}


CTriangle2d::~CTriangle2d()
{

}


boolean CTriangle2d::Sweep( const CVector2d& t0v0, const CVector2d& t0v1, const CVector2d& t0v2,  
								 const CVector2d& t1v0, const CVector2d& t1v1, const CVector2d& t1v2, 
								 const CVector2d& v1, const CVector2d& v2, fixed &u )
{
	//boolean intersects = FALSE;
	ASSERT ( FALSE );
	return FALSE;
}

// http://jgt.akpeters.com/papers/Moller97/tritri.html

boolean CTriangle2d::Intersects( const CVector2d& t0v0, const CVector2d& t0v1, const CVector2d& t0v2, 
								 const CVector2d& t1v0, const CVector2d& t1v1, const CVector2d& t1v2 )
{
	// we check all the edges of t0 with t1
	fixed u,v;
	
	if ( Intersects( t1v0, t1v1, t1v2, t0v0, t0v1, u ,v ) ) 
	{
		if ( u >= 0 && v >= 0 && u <= CMathFixed::One && v <= CMathFixed::One )
			return TRUE;
	}

	if ( Intersects( t1v0, t1v1, t1v2, t0v1, t0v2, u, v ) ) 
	{
		if ( u >= 0 && v >= 0 && u <= CMathFixed::One && v <= CMathFixed::One )
			return TRUE;
	}
	if ( Intersects( t1v0, t1v1, t1v2, t0v2, t0v0, u, v ) ) 
	{
		if ( u >= 0 && v >= 0 && u <= CMathFixed::One && v <= CMathFixed::One )
			return TRUE;
	}

	// finally we check whether the triangle is completely inside the other triangle
	if ( DetermineSpace( t0v0, t0v1, t0v2, t1v0 ) == CSpace::Inside ) return TRUE;
	if ( DetermineSpace( t1v0, t1v1, t1v2, t0v0 ) == CSpace::Inside ) return TRUE;

	return FALSE;

}


boolean CTriangle2d::Intersects( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, 
								 const CVector2d& v0, const CVector2d& v1, fixed& u, fixed& v )
{
	if ( CLineSegment2d::Intersects( tv0, tv1, v0, v1, &u, &v ) ) 
	{
			return TRUE;
	}

	if ( CLineSegment2d::Intersects( tv1, tv2, v0, v1, &u ,&v ) )
	{
			return TRUE;
	}

	if ( CLineSegment2d::Intersects( tv2, tv0, v0, v1, &u, &v ) )
	{
			return TRUE;
	}

	return FALSE;
}


CSpace::Relativity CTriangle2d::DetermineSpace( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, const CVector2d& pt )
{
	fixed a = IsLeft( tv0, tv1, pt );
	fixed b = IsLeft( tv1, tv2, pt );

	if ( CMathFixed::Mul( a,b ) < 0 )
		return CSpace::Outside;

	fixed c = IsLeft( tv2, tv1, pt );

	if ( CMathFixed::Mul( b,c ) < 0  )
		return CSpace::Outside;

	return CSpace::Inside;
}


CSpace::Relativity CTriangle2d::DetermineSpace( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, 
								     const CVector2d& v0, const CVector2d& v1  )
{
	fixed u,v;
	if ( CLineSegment2d::Intersects( v0, v1, tv0, tv1, &u, &v ) ) 
	{
		if ( u >= 0 && v >= 0 && u <= CMathFixed::One && v <= CMathFixed::One )
			return CSpace::Intersecting;
	}

	if ( CLineSegment2d::Intersects( v0, v1, tv1, tv2, &u ,&v ) )
	{
		if ( u >= 0 && v >= 0 && u <= CMathFixed::One && v <= CMathFixed::One )
			return CSpace::Intersecting;
	}

	if ( CLineSegment2d::Intersects( v0, v1, tv2, tv0, &u, &v ) )
	{
		if ( u >= 0 && v >= 0 && u <= CMathFixed::One && v <= CMathFixed::One )
			return CSpace::Intersecting;
	}

	// check whether segment doesnt completely lie inside the triangle
	if ( DetermineSpace( tv0, tv1, tv2, v0 ) == CSpace::Inside ) 
		return CSpace::Inside;

	return CSpace::Outside;
}


void CTriangle2d::Barycentric( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, const CVector2d& p, fixed &u, fixed &v, fixed &w )
{
	CVector2d v0 = tv1 - tv0;
	CVector2d v1 = tv2 - tv0;
	CVector2d v2 = p - tv0;

	fixed d00 = v0 * v0;
	fixed d01 = v0 * v1;
	fixed d11 = v1 * v1;
	fixed d20 = v2 * v0;
	fixed d21 = v2 * v1;

	fixed oneoverdenom = CMathFixed::Div( CMathFixed::One, CMathFixed::Mul( d00, d11 ) - CMathFixed::Mul( d01, d01 ) );

	v = CMathFixed::Mul( oneoverdenom, CMathFixed::Mul( d11, d20 ) - CMathFixed::Mul( d01, d21) );
	w = CMathFixed::Mul( oneoverdenom, CMathFixed::Mul( d00, d21 ) - CMathFixed::Mul( d01, d20 ) );
	u = CMathFixed::One - w - v;
}


boolean CTriangle2d::IsIsoceles() const
{
	CVector2d A = m_v1 - m_v0;
	CVector2d B = m_v2 - m_v0;
	CVector2d C = m_v2 - m_v1;
    
	fixed AA = A * A;
	fixed BB = B * B;
	fixed CC = C * C;
	
	if ( AA == BB || AA == CC || BB == CC )
		return TRUE;
	else return FALSE;
}


boolean CTriangle2d::IsEquilateral() const
{
	CVector2d A = m_v1 - m_v0;
	CVector2d B = m_v2 - m_v0;
	CVector2d C = m_v2 - m_v1;
    
	fixed AA = A * A;
	
	if ( AA == B * B && AA == C * C )
		return TRUE;
	else return FALSE;
}
	

void CTriangle2d::ComputeIncenter( CVector2d& outPoint ) const
{
	ASSERT ( FALSE );
}


void CTriangle2d::ComputeIncircle( CCircle& outCircle ) const
{
	ASSERT ( FALSE );
}


void CTriangle2d::ComputeCircumcenter( CVector2d& outPoint ) const
{
	ASSERT ( FALSE );
}


void CTriangle2d::ComputerCircumcircle( CCircle& outCircle ) const
{
	ASSERT ( FALSE );
}